﻿
INLINE VOID AlphaBlendFullLevelMMX(LPCWORD, LPWORD, LPCBYTE);
INLINE VOID AlphaBlend32LevelMMX(LPCWORD, LPWORD, LPCBYTE);

//////////////////////////////////////////////////////////////////////////

INLINE VOID AlphaBlendFullLevelMMX(LPCWORD src, LPWORD dest, LPCBYTE alpha)
{
	static const QWORD COLORMASK = 0x001f0000f80007e0;

	if (!*alpha)
		return;

	if (*alpha == 0xff)
	{
		*dest = *src;
		return;
	}

	// 公式 dest = (src - dest) * alpha / 256 + dest
	__asm
	{
#if BAD
		// 初始化MMX
		emms
		movzx		ecx, alpha
		movq		mm7, COLORMASK	// mm6 = mask

		// 装载像素到mm0和mm1
		mov			edi, dest
		mov			ax, [edi]
		movd		mm0, src		// mm0 = src
		movd		mm1, eax		// mm1 = dest

		// 分组扩展像素
		punpcklwd	mm0, mm0		// mm0 = ..cc
		punpckldq	mm0, mm0		// mm0 = cccc
		pand		mm0, mm7		// mm0 = b.rg
		punpcklwd	mm1, mm1		// mm1 = ..cc
		punpckldq	mm1, mm1		// mm1 = cccc
		pand		mm1, mm7		// mm1 = b.rg

		// 混色计算
		psubw		mm0, mm1		// mm0 = src - dest
		movd		eax, mm0		// MMX指令集没有无符号16位乘法，也没32位乘法……只好用X86的MUL/IMUL
		psrlq		mm0, 32			// 由于MMX寄存器修改后需经过2个时钟周期才能放进通用寄存器，提前到这里执行
		mul			ecx
		movd		mm2, eax		// mm2 = rrgg
		movd		eax, mm0
		mul			ecx
		movd		mm0, eax		// mm0 = bbxx
		punpckldq	mm2, mm0		// mm2 = bbxxrrgg
		psrld		mm2, 8			// mm2 = bxrg
		paddw		mm2, mm1		// + dest
		pand		mm2, mm7		// mm2 = b.rg
		movq		mm0, mm2
		punpckhdq	mm0, mm0		// mm0 = b.b.
		por			mm0, mm2		// mm0 = b.cc = b.[r.b.g.]
		punpcklwd	mm0, mm0		// mm0 = [r.b][r.b][.g.][.g.]
		punpckhdq	mm0, mm0		// mm0 = [r.b][r.b][r.b][r.b]
		por			mm0, mm2		// mm0 = [r.b][r.b][r.b][rgb] = xxxc

		// 终止MMX
		movd		eax, mm0
		emms
		mov			[edi], ax
#endif
	}
}

// TODO: 考虑未来加入64位支持（使用64位通用寄存器，也许可以提高性能）
INLINE VOID AlphaBlend32LevelMMX(LPCWORD src, LPWORD dest, LPCBYTE alpha)
{
	// mm4 = COLORMASK (07E0F81F07E0F81Fh)

	// 公式 dest = (src - dest) * alpha / 32 + dest
	// 一次同时计算2个像素
	__asm
	{
		// 装载APLHA
		mov			esi, alpha
		xor			ecx, ecx
		mov			cx, [esi]		// Axax
		jcxz		quit			// 如果两个像素都是全透明，不作处理
		mov			esi, src
		mov			edi, dest
		xor			ebx, ebx
		mov			bl, ch			// ..Ax
		xor			ch, ch			// ..ax
		add			ebx, 4			// ALPHA误差补正
		add			ecx, 4			// ALPHA误差补正
		shr			ebx, 3			// ...A
		shr			ecx, 3			// ...a

		// 分别一次性装载源和目标的2个像素到mm0和mm1
		movd		mm0, [esi]		// [......][RGBrgb]
		movd		mm1, [edi]		// [......][RGBrgb]

		// 分组扩展像素
		punpcklwd	mm0, mm0		// [RGBRGB][rgbrgb]
		pand		mm0, mm4		// [.G.R.B][.g.r.b]
		punpcklwd	mm1, mm1		// [RGBRGB][rgbrgb]
		pand		mm1, mm4		// [.G.R.B][.g.r.b]

		// 混色计算
		// MMX指令集没有无符号16位乘法，也没32位乘法……只好用X86的MUL/IMUL
		psubd		mm0, mm1		// mm0 = src - dest
		movd		eax, mm0
		psrlq		mm0, 32			// MMX寄存器修改后需经过2个时钟周期才能放进通用寄存器，提前到这里执行
		mul			ecx
		movd		mm2, eax		// [......][gxrxbx]
		movd		eax, mm0
		mul			ebx
		movd		mm3, eax		// [......][GxRxBx]
		punpckldq	mm2, mm3		// [GxRxBx][gxrxbx]
		psrld		mm2, 5			// [.GxRxB][.gxrxb]
		paddd		mm2, mm1		// + dest
		pand		mm2, mm4		// [.G.R.B][.g.r.b]

		// 恢复像素
		movq		mm1, mm2
		psrld		mm1, 16			// [....G.][....g.]
		por			mm2, mm1		// [.G.RGB][.g.rgb]
		movq		mm1, mm2
		punpckhdq	mm1, mm1		// [.G.RGB][.G.RGB]
		punpcklwd	mm2, mm1		// [.G..g.][RGBrgb]

		// 保存结果
		movd		[edi], mm2		// [RGBrgb]

quit:
	}
}

//////////////////////////////////////////////////////////////////////////
